/*
 * wav.c
 *
 *  Created on: Apr 27, 2011
 *      Author: tommy
 */

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <assert.h>
#include "include/wav.h"

void assertSizes();

wavT *
loadWavFile(char * wavfile)
{
	FILE * wfile;
	wavT * wav;

	if ( (wav = calloc(1, sizeof(wavT))) == NULL )
	{
		fprintf(stderr, "Out of memory\n");
		return NULL;
	}

	if ( (wfile = fopen(wavfile, "r")) == NULL)
	{
		free(wav);
		return NULL;
	}

	if (fread(&wav -> riff_desc, sizeof(RIFF_CK), 1, wfile) != 1)
	{
		free(wav);
		fclose(wfile);
		fprintf(stderr,"Error reading riff header\n");
		return NULL;
	}

	// From now on, fields transformed by ntohl are due to their big endian representation in file, while in memory needs to be little endian
	wav -> riff_desc.chunkID = ntohl(wav -> riff_desc.chunkID);
	wav -> riff_desc.format = ntohl(wav -> riff_desc.format);

	// Reads the whole format chunk EXCEPT the fields extraParamSize and extraParams, since all wavs are PCM
	if (fread(&wav -> fmt, sizeof(FMT_CK),1,wfile) != 1)
	{
		free(wav);
		fclose(wfile);
		fprintf(stderr, "Error reading Format chunk\n");
		return NULL;
	}

	// After reading whole format chunk, allocs space for extraParams acoording to extraParamSize field
	wav -> fmt.chunkID = ntohl(wav -> fmt.chunkID);

	// Reads data chunkID
	if (fread(&wav -> data.chunkID, sizeof(CKID),1,wfile) != 1)
	{
		free(wav);
		fclose(wfile);
		fprintf(stderr, "Error reading data chunkid\n");
		return NULL;
	}
	wav -> data.chunkID = ntohl(wav -> data.chunkID);

	// Reads data chunkSize
	if (fread(&wav -> data.chunkSize, sizeof(CKSIZE),1,wfile) != 1)
	{
		free(wav);
		fclose(wfile);
		fprintf(stderr, "Error reading data chunksize\n");
		return NULL;
	}

	// Allocs space and stores sound data in it. On error, free space and abort
	if ( (wav -> data.soundData = calloc(1, wav -> data.chunkSize)) == NULL )
	{
		free(wav);
		fclose(wfile);
		fprintf(stderr, "Out of memory\n");
		return NULL;
	}

	if (fread(wav -> data.soundData, wav -> data.chunkSize, 1, wfile) != 1)
	{
		free(wav -> data.soundData);
		free(wav);
		fclose(wfile);
		fprintf(stderr, "Error reading sound data\n");
		return NULL;
	}

	fclose(wfile);
	return wav;
}

int
saveWavFile(char * wavfile, wavT * wav)
{
	FILE * wfile;

	if ( (wfile = fopen(wavfile, "w+")) == NULL)
	{
		return 0;
	}

	// save RIFF header
	wav -> riff_desc.chunkID = htonl(wav -> riff_desc.chunkID);
	wav -> riff_desc.format = htonl(wav -> riff_desc.format);
	fwrite(&wav -> riff_desc, sizeof(RIFF_CK), 1, wfile);

	// save FMT
	wav -> fmt.chunkID = htonl(wav -> fmt.chunkID);
	fwrite(&wav -> fmt, sizeof(FMT_CK), 1, wfile);

	// save DATA
	wav->data.chunkID = htonl(wav->data.chunkID);
	fwrite(&wav->data.chunkID, sizeof(CKID), 1, wfile);
	fwrite(&wav->data.chunkSize, sizeof(CKSIZE), 1, wfile);
	fwrite(wav->data.soundData, wav->data.chunkSize, 1, wfile);

	// leave wav unmodified
	wav -> riff_desc.chunkID = ntohl(wav -> riff_desc.chunkID);
	wav -> riff_desc.format = ntohl(wav -> riff_desc.format);
	wav -> fmt.chunkID = ntohl(wav -> fmt.chunkID);
	wav -> data.chunkID = ntohl(wav -> data.chunkID);

	fclose(wfile);
	return 1;
}

void
assertSizes()
{
	assert(sizeof(BYTE) == 1);
	assert(sizeof(WORD) == 2);
	assert(sizeof(DWORD) == 4);
}
